
package com.fsck.k9.mail.internet;

import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.mail.*;
import org.apache.commons.io.IOUtils;
import org.apache.james.mime4j.decoder.Base64InputStream;
import org.apache.james.mime4j.decoder.DecoderUtil;
import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.regex.Pattern;
import java.nio.charset.Charset;


public class MimeUtility
{
    public static final String DEFAULT_ATTACHMENT_MIME_TYPE = "application/octet-stream";



    /*
     * http://www.w3schools.com/media/media_mimeref.asp
     * +
     * http://www.stdicon.com/mimetypes
     */
    public static final String[][] MIME_TYPE_BY_EXTENSION_MAP = new String[][]
    {
        { "", "application/octet-stream" },
        { "123", "application/vnd.lotus-1-2-3"},
        { "323", "text/h323"},
        { "3dml", "text/vnd.in3d.3dml"},
        { "3g2", "video/3gpp2"},
        { "3gp", "video/3gpp"},
        { "aab", "application/x-authorware-bin"},
        { "aac", "audio/x-aac"},
        { "aam", "application/x-authorware-map"},
        { "a", "application/octet-stream"},
        { "aas", "application/x-authorware-seg"},
        { "abw", "application/x-abiword"},
        { "acc", "application/vnd.americandynamics.acc"},
        { "ace", "application/x-ace-compressed"},
        { "acu", "application/vnd.acucobol"},
        { "acutc", "application/vnd.acucorp"},
        { "acx", "application/internet-property-stream"},
        { "adp", "audio/adpcm"},
        { "aep", "application/vnd.audiograph"},
        { "afm", "application/x-font-type1"},
        { "afp", "application/vnd.ibm.modcap"},
        { "ai", "application/postscript"},
        { "aif", "audio/x-aiff"},
        { "aifc", "audio/x-aiff"},
        { "aiff", "audio/x-aiff"},
        { "air", "application/vnd.adobe.air-application-installer-package+zip"},
        { "ami", "application/vnd.amiga.ami"},
        { "apk", "application/vnd.android.package-archive"},
        { "application", "application/x-ms-application"},
        { "apr", "application/vnd.lotus-approach"},
        { "asc", "application/pgp-signature"},
        { "asf", "video/x-ms-asf"},
        { "asm", "text/x-asm"},
        { "aso", "application/vnd.accpac.simply.aso"},
        { "asr", "video/x-ms-asf"},
        { "asx", "video/x-ms-asf"},
        { "atc", "application/vnd.acucorp"},
        { "atom", "application/atom+xml"},
        { "atomcat", "application/atomcat+xml"},
        { "atomsvc", "application/atomsvc+xml"},
        { "atx", "application/vnd.antix.game-component"},
        { "au", "audio/basic"},
        { "avi", "video/x-msvideo"},
        { "aw", "application/applixware"},
        { "axs", "application/olescript"},
        { "azf", "application/vnd.airzip.filesecure.azf"},
        { "azs", "application/vnd.airzip.filesecure.azs"},
        { "azw", "application/vnd.amazon.ebook"},
        { "bas", "text/plain"},
        { "bat", "application/x-msdownload"},
        { "bcpio", "application/x-bcpio"},
        { "bdf", "application/x-font-bdf"},
        { "bdm", "application/vnd.syncml.dm+wbxml"},
        { "bh2", "application/vnd.fujitsu.oasysprs"},
        { "bin", "application/octet-stream"},
        { "bmi", "application/vnd.bmi"},
        { "bmp", "image/bmp"},
        { "book", "application/vnd.framemaker"},
        { "box", "application/vnd.previewsystems.box"},
        { "boz", "application/x-bzip2"},
        { "bpk", "application/octet-stream"},
        { "btif", "image/prs.btif"},
        { "bz2", "application/x-bzip2"},
        { "bz", "application/x-bzip"},
        { "c4d", "application/vnd.clonk.c4group"},
        { "c4f", "application/vnd.clonk.c4group"},
        { "c4g", "application/vnd.clonk.c4group"},
        { "c4p", "application/vnd.clonk.c4group"},
        { "c4u", "application/vnd.clonk.c4group"},
        { "cab", "application/vnd.ms-cab-compressed"},
        { "car", "application/vnd.curl.car"},
        { "cat", "application/vnd.ms-pki.seccat"},
        { "cct", "application/x-director"},
        { "cc", "text/x-c"},
        { "ccxml", "application/ccxml+xml"},
        { "cdbcmsg", "application/vnd.contact.cmsg"},
        { "cdf", "application/x-cdf"},
        { "cdkey", "application/vnd.mediastation.cdkey"},
        { "cdx", "chemical/x-cdx"},
        { "cdxml", "application/vnd.chemdraw+xml"},
        { "cdy", "application/vnd.cinderella"},
        { "cer", "application/x-x509-ca-cert"},
        { "cgm", "image/cgm"},
        { "chat", "application/x-chat"},
        { "chm", "application/vnd.ms-htmlhelp"},
        { "chrt", "application/vnd.kde.kchart"},
        { "cif", "chemical/x-cif"},
        { "cii", "application/vnd.anser-web-certificate-issue-initiation"},
        { "cla", "application/vnd.claymore"},
        { "class", "application/java-vm"},
        { "clkk", "application/vnd.crick.clicker.keyboard"},
        { "clkp", "application/vnd.crick.clicker.palette"},
        { "clkt", "application/vnd.crick.clicker.template"},
        { "clkw", "application/vnd.crick.clicker.wordbank"},
        { "clkx", "application/vnd.crick.clicker"},
        { "clp", "application/x-msclip"},
        { "cmc", "application/vnd.cosmocaller"},
        { "cmdf", "chemical/x-cmdf"},
        { "cml", "chemical/x-cml"},
        { "cmp", "application/vnd.yellowriver-custom-menu"},
        { "cmx", "image/x-cmx"},
        { "cod", "application/vnd.rim.cod"},
        { "com", "application/x-msdownload"},
        { "conf", "text/plain"},
        { "cpio", "application/x-cpio"},
        { "cpp", "text/x-c"},
        { "cpt", "application/mac-compactpro"},
        { "crd", "application/x-mscardfile"},
        { "crl", "application/pkix-crl"},
        { "crt", "application/x-x509-ca-cert"},
        { "csh", "application/x-csh"},
        { "csml", "chemical/x-csml"},
        { "csp", "application/vnd.commonspace"},
        { "css", "text/css"},
        { "cst", "application/x-director"},
        { "csv", "text/csv"},
        { "c", "text/plain"},
        { "cu", "application/cu-seeme"},
        { "curl", "text/vnd.curl"},
        { "cww", "application/prs.cww"},
        { "cxt", "application/x-director"},
        { "cxx", "text/x-c"},
        { "daf", "application/vnd.mobius.daf"},
        { "dataless", "application/vnd.fdsn.seed"},
        { "davmount", "application/davmount+xml"},
        { "dcr", "application/x-director"},
        { "dcurl", "text/vnd.curl.dcurl"},
        { "dd2", "application/vnd.oma.dd2+xml"},
        { "ddd", "application/vnd.fujixerox.ddd"},
        { "deb", "application/x-debian-package"},
        { "def", "text/plain"},
        { "deploy", "application/octet-stream"},
        { "der", "application/x-x509-ca-cert"},
        { "dfac", "application/vnd.dreamfactory"},
        { "dic", "text/x-c"},
        { "diff", "text/plain"},
        { "dir", "application/x-director"},
        { "dis", "application/vnd.mobius.dis"},
        { "dist", "application/octet-stream"},
        { "distz", "application/octet-stream"},
        { "djv", "image/vnd.djvu"},
        { "djvu", "image/vnd.djvu"},
        { "dll", "application/x-msdownload"},
        { "dmg", "application/octet-stream"},
        { "dms", "application/octet-stream"},
        { "dna", "application/vnd.dna"},
        { "doc", "application/msword"},
        { "docm", "application/vnd.ms-word.document.macroenabled.12"},
        { "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
        { "dot", "application/msword"},
        { "dotm", "application/vnd.ms-word.template.macroenabled.12"},
        { "dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
        { "dp", "application/vnd.osgi.dp"},
        { "dpg", "application/vnd.dpgraph"},
        { "dsc", "text/prs.lines.tag"},
        { "dtb", "application/x-dtbook+xml"},
        { "dtd", "application/xml-dtd"},
        { "dts", "audio/vnd.dts"},
        { "dtshd", "audio/vnd.dts.hd"},
        { "dump", "application/octet-stream"},
        { "dvi", "application/x-dvi"},
        { "dwf", "model/vnd.dwf"},
        { "dwg", "image/vnd.dwg"},
        { "dxf", "image/vnd.dxf"},
        { "dxp", "application/vnd.spotfire.dxp"},
        { "dxr", "application/x-director"},
        { "ecelp4800", "audio/vnd.nuera.ecelp4800"},
        { "ecelp7470", "audio/vnd.nuera.ecelp7470"},
        { "ecelp9600", "audio/vnd.nuera.ecelp9600"},
        { "ecma", "application/ecmascript"},
        { "edm", "application/vnd.novadigm.edm"},
        { "edx", "application/vnd.novadigm.edx"},
        { "efif", "application/vnd.picsel"},
        { "ei6", "application/vnd.pg.osasli"},
        { "elc", "application/octet-stream"},
        { "eml", "message/rfc822"},
        { "emma", "application/emma+xml"},
        { "eol", "audio/vnd.digital-winds"},
        { "eot", "application/vnd.ms-fontobject"},
        { "eps", "application/postscript"},
        { "epub", "application/epub+zip"},
        { "es3", "application/vnd.eszigno3+xml"},
        { "esf", "application/vnd.epson.esf"},
        { "et3", "application/vnd.eszigno3+xml"},
        { "etx", "text/x-setext"},
        { "evy", "application/envoy"},
        { "exe", "application/octet-stream"},
        { "ext", "application/vnd.novadigm.ext"},
        { "ez2", "application/vnd.ezpix-album"},
        { "ez3", "application/vnd.ezpix-package"},
        { "ez", "application/andrew-inset"},
        { "f4v", "video/x-f4v"},
        { "f77", "text/x-fortran"},
        { "f90", "text/x-fortran"},
        { "fbs", "image/vnd.fastbidsheet"},
        { "fdf", "application/vnd.fdf"},
        { "fe_launch", "application/vnd.denovo.fcselayout-link"},
        { "fg5", "application/vnd.fujitsu.oasysgp"},
        { "fgd", "application/x-director"},
        { "fh4", "image/x-freehand"},
        { "fh5", "image/x-freehand"},
        { "fh7", "image/x-freehand"},
        { "fhc", "image/x-freehand"},
        { "fh", "image/x-freehand"},
        { "fif", "application/fractals"},
        { "fig", "application/x-xfig"},
        { "fli", "video/x-fli"},
        { "flo", "application/vnd.micrografx.flo"},
        { "flr", "x-world/x-vrml"},
        { "flv", "video/x-flv"},
        { "flw", "application/vnd.kde.kivio"},
        { "flx", "text/vnd.fmi.flexstor"},
        { "fly", "text/vnd.fly"},
        { "fm", "application/vnd.framemaker"},
        { "fnc", "application/vnd.frogans.fnc"},
        { "for", "text/x-fortran"},
        { "fpx", "image/vnd.fpx"},
        { "frame", "application/vnd.framemaker"},
        { "fsc", "application/vnd.fsc.weblaunch"},
        { "fst", "image/vnd.fst"},
        { "ftc", "application/vnd.fluxtime.clip"},
        { "f", "text/x-fortran"},
        { "fti", "application/vnd.anser-web-funds-transfer-initiation"},
        { "fvt", "video/vnd.fvt"},
        { "fzs", "application/vnd.fuzzysheet"},
        { "g3", "image/g3fax"},
        { "gac", "application/vnd.groove-account"},
        { "gdl", "model/vnd.gdl"},
        { "geo", "application/vnd.dynageo"},
        { "gex", "application/vnd.geometry-explorer"},
        { "ggb", "application/vnd.geogebra.file"},
        { "ggt", "application/vnd.geogebra.tool"},
        { "ghf", "application/vnd.groove-help"},
        { "gif", "image/gif"},
        { "gim", "application/vnd.groove-identity-message"},
        { "gmx", "application/vnd.gmx"},
        { "gnumeric", "application/x-gnumeric"},
        { "gph", "application/vnd.flographit"},
        { "gqf", "application/vnd.grafeq"},
        { "gqs", "application/vnd.grafeq"},
        { "gram", "application/srgs"},
        { "gre", "application/vnd.geometry-explorer"},
        { "grv", "application/vnd.groove-injector"},
        { "grxml", "application/srgs+xml"},
        { "gsf", "application/x-font-ghostscript"},
        { "gtar", "application/x-gtar"},
        { "gtm", "application/vnd.groove-tool-message"},
        { "gtw", "model/vnd.gtw"},
        { "gv", "text/vnd.graphviz"},
        { "gz", "application/x-gzip"},
        { "h261", "video/h261"},
        { "h263", "video/h263"},
        { "h264", "video/h264"},
        { "hbci", "application/vnd.hbci"},
        { "hdf", "application/x-hdf"},
        { "hh", "text/x-c"},
        { "hlp", "application/winhlp"},
        { "hpgl", "application/vnd.hp-hpgl"},
        { "hpid", "application/vnd.hp-hpid"},
        { "hps", "application/vnd.hp-hps"},
        { "hqx", "application/mac-binhex40"},
        { "hta", "application/hta"},
        { "htc", "text/x-component"},
        { "h", "text/plain"},
        { "htke", "application/vnd.kenameaapp"},
        { "html", "text/html"},
        { "htm", "text/html"},
        { "htt", "text/webviewhtml"},
        { "hvd", "application/vnd.yamaha.hv-dic"},
        { "hvp", "application/vnd.yamaha.hv-voice"},
        { "hvs", "application/vnd.yamaha.hv-script"},
        { "icc", "application/vnd.iccprofile"},
        { "ice", "x-conference/x-cooltalk"},
        { "icm", "application/vnd.iccprofile"},
        { "ico", "image/x-icon"},
        { "ics", "text/calendar"},
        { "ief", "image/ief"},
        { "ifb", "text/calendar"},
        { "ifm", "application/vnd.shana.informed.formdata"},
        { "iges", "model/iges"},
        { "igl", "application/vnd.igloader"},
        { "igs", "model/iges"},
        { "igx", "application/vnd.micrografx.igx"},
        { "iif", "application/vnd.shana.informed.interchange"},
        { "iii", "application/x-iphone"},
        { "imp", "application/vnd.accpac.simply.imp"},
        { "ims", "application/vnd.ms-ims"},
        { "ins", "application/x-internet-signup"},
        { "in", "text/plain"},
        { "ipk", "application/vnd.shana.informed.package"},
        { "irm", "application/vnd.ibm.rights-management"},
        { "irp", "application/vnd.irepository.package+xml"},
        { "iso", "application/octet-stream"},
        { "isp", "application/x-internet-signup"},
        { "itp", "application/vnd.shana.informed.formtemplate"},
        { "ivp", "application/vnd.immervision-ivp"},
        { "ivu", "application/vnd.immervision-ivu"},
        { "jad", "text/vnd.sun.j2me.app-descriptor"},
        { "jam", "application/vnd.jam"},
        { "jar", "application/java-archive"},
        { "java", "text/x-java-source"},
        { "jfif", "image/pipeg"},
        { "jisp", "application/vnd.jisp"},
        { "jlt", "application/vnd.hp-jlyt"},
        { "jnlp", "application/x-java-jnlp-file"},
        { "joda", "application/vnd.joost.joda-archive"},
        { "jpeg", "image/jpeg"},
        { "jpe", "image/jpeg"},
        { "jpg", "image/jpeg"},
        { "jpgm", "video/jpm"},
        { "jpgv", "video/jpeg"},
        { "jpm", "video/jpm"},
        { "js", "application/x-javascript"},
        { "json", "application/json"},
        { "kar", "audio/midi"},
        { "karbon", "application/vnd.kde.karbon"},
        { "kfo", "application/vnd.kde.kformula"},
        { "kia", "application/vnd.kidspiration"},
        { "kil", "application/x-killustrator"},
        { "kml", "application/vnd.google-earth.kml+xml"},
        { "kmz", "application/vnd.google-earth.kmz"},
        { "kne", "application/vnd.kinar"},
        { "knp", "application/vnd.kinar"},
        { "kon", "application/vnd.kde.kontour"},
        { "kpr", "application/vnd.kde.kpresenter"},
        { "kpt", "application/vnd.kde.kpresenter"},
        { "ksh", "text/plain"},
        { "ksp", "application/vnd.kde.kspread"},
        { "ktr", "application/vnd.kahootz"},
        { "ktz", "application/vnd.kahootz"},
        { "kwd", "application/vnd.kde.kword"},
        { "kwt", "application/vnd.kde.kword"},
        { "latex", "application/x-latex"},
        { "lbd", "application/vnd.llamagraphics.life-balance.desktop"},
        { "lbe", "application/vnd.llamagraphics.life-balance.exchange+xml"},
        { "les", "application/vnd.hhe.lesson-player"},
        { "lha", "application/octet-stream"},
        { "link66", "application/vnd.route66.link66+xml"},
        { "list3820", "application/vnd.ibm.modcap"},
        { "listafp", "application/vnd.ibm.modcap"},
        { "list", "text/plain"},
        { "log", "text/plain"},
        { "lostxml", "application/lost+xml"},
        { "lrf", "application/octet-stream"},
        { "lrm", "application/vnd.ms-lrm"},
        { "lsf", "video/x-la-asf"},
        { "lsx", "video/x-la-asf"},
        { "ltf", "application/vnd.frogans.ltf"},
        { "lvp", "audio/vnd.lucent.voice"},
        { "lwp", "application/vnd.lotus-wordpro"},
        { "lzh", "application/octet-stream"},
        { "m13", "application/x-msmediaview"},
        { "m14", "application/x-msmediaview"},
        { "m1v", "video/mpeg"},
        { "m2a", "audio/mpeg"},
        { "m2v", "video/mpeg"},
        { "m3a", "audio/mpeg"},
        { "m3u", "audio/x-mpegurl"},
        { "m4u", "video/vnd.mpegurl"},
        { "m4v", "video/x-m4v"},
        { "ma", "application/mathematica"},
        { "mag", "application/vnd.ecowin.chart"},
        { "maker", "application/vnd.framemaker"},
        { "man", "text/troff"},
        { "mathml", "application/mathml+xml"},
        { "mb", "application/mathematica"},
        { "mbk", "application/vnd.mobius.mbk"},
        { "mbox", "application/mbox"},
        { "mc1", "application/vnd.medcalcdata"},
        { "mcd", "application/vnd.mcd"},
        { "mcurl", "text/vnd.curl.mcurl"},
        { "mdb", "application/x-msaccess"},
        { "mdi", "image/vnd.ms-modi"},
        { "mesh", "model/mesh"},
        { "me", "text/troff"},
        { "mfm", "application/vnd.mfmp"},
        { "mgz", "application/vnd.proteus.magazine"},
        { "mht", "message/rfc822"},
        { "mhtml", "message/rfc822"},
        { "mid", "audio/midi"},
        { "midi", "audio/midi"},
        { "mif", "application/vnd.mif"},
        { "mime", "message/rfc822"},
        { "mj2", "video/mj2"},
        { "mjp2", "video/mj2"},
        { "mlp", "application/vnd.dolby.mlp"},
        { "mmd", "application/vnd.chipnuts.karaoke-mmd"},
        { "mmf", "application/vnd.smaf"},
        { "mmr", "image/vnd.fujixerox.edmics-mmr"},
        { "mny", "application/x-msmoney"},
        { "mobi", "application/x-mobipocket-ebook"},
        { "movie", "video/x-sgi-movie"},
        { "mov", "video/quicktime"},
        { "mp2a", "audio/mpeg"},
        { "mp2", "video/mpeg"},
        { "mp3", "audio/mpeg"},
        { "mp4a", "audio/mp4"},
        { "mp4s", "application/mp4"},
        { "mp4", "video/mp4"},
        { "mp4v", "video/mp4"},
        { "mpa", "video/mpeg"},
        { "mpc", "application/vnd.mophun.certificate"},
        { "mpeg", "video/mpeg"},
        { "mpe", "video/mpeg"},
        { "mpg4", "video/mp4"},
        { "mpga", "audio/mpeg"},
        { "mpg", "video/mpeg"},
        { "mpkg", "application/vnd.apple.installer+xml"},
        { "mpm", "application/vnd.blueice.multipass"},
        { "mpn", "application/vnd.mophun.application"},
        { "mpp", "application/vnd.ms-project"},
        { "mpt", "application/vnd.ms-project"},
        { "mpv2", "video/mpeg"},
        { "mpy", "application/vnd.ibm.minipay"},
        { "mqy", "application/vnd.mobius.mqy"},
        { "mrc", "application/marc"},
        { "mscml", "application/mediaservercontrol+xml"},
        { "mseed", "application/vnd.fdsn.mseed"},
        { "mseq", "application/vnd.mseq"},
        { "msf", "application/vnd.epson.msf"},
        { "msh", "model/mesh"},
        { "msi", "application/x-msdownload"},
        { "ms", "text/troff"},
        { "msty", "application/vnd.muvee.style"},
        { "mts", "model/vnd.mts"},
        { "mus", "application/vnd.musician"},
        { "musicxml", "application/vnd.recordare.musicxml+xml"},
        { "mvb", "application/x-msmediaview"},
        { "mxf", "application/mxf"},
        { "mxl", "application/vnd.recordare.musicxml"},
        { "mxml", "application/xv+xml"},
        { "mxs", "application/vnd.triscape.mxs"},
        { "mxu", "video/vnd.mpegurl"},
        { "nb", "application/mathematica"},
        { "nc", "application/x-netcdf"},
        { "ncx", "application/x-dtbncx+xml"},
        { "n-gage", "application/vnd.nokia.n-gage.symbian.install"},
        { "ngdat", "application/vnd.nokia.n-gage.data"},
        { "nlu", "application/vnd.neurolanguage.nlu"},
        { "nml", "application/vnd.enliven"},
        { "nnd", "application/vnd.noblenet-directory"},
        { "nns", "application/vnd.noblenet-sealer"},
        { "nnw", "application/vnd.noblenet-web"},
        { "npx", "image/vnd.net-fpx"},
        { "nsf", "application/vnd.lotus-notes"},
        { "nws", "message/rfc822"},
        { "oa2", "application/vnd.fujitsu.oasys2"},
        { "oa3", "application/vnd.fujitsu.oasys3"},
        { "o", "application/octet-stream"},
        { "oas", "application/vnd.fujitsu.oasys"},
        { "obd", "application/x-msbinder"},
        { "obj", "application/octet-stream"},
        { "oda", "application/oda"},
        { "odb", "application/vnd.oasis.opendocument.database"},
        { "odc", "application/vnd.oasis.opendocument.chart"},
        { "odf", "application/vnd.oasis.opendocument.formula"},
        { "odft", "application/vnd.oasis.opendocument.formula-template"},
        { "odg", "application/vnd.oasis.opendocument.graphics"},
        { "odi", "application/vnd.oasis.opendocument.image"},
        { "odp", "application/vnd.oasis.opendocument.presentation"},
        { "ods", "application/vnd.oasis.opendocument.spreadsheet"},
        { "odt", "application/vnd.oasis.opendocument.text"},
        { "oga", "audio/ogg"},
        { "ogg", "audio/ogg"},
        { "ogv", "video/ogg"},
        { "ogx", "application/ogg"},
        { "onepkg", "application/onenote"},
        { "onetmp", "application/onenote"},
        { "onetoc2", "application/onenote"},
        { "onetoc", "application/onenote"},
        { "opf", "application/oebps-package+xml"},
        { "oprc", "application/vnd.palm"},
        { "org", "application/vnd.lotus-organizer"},
        { "osf", "application/vnd.yamaha.openscoreformat"},
        { "osfpvg", "application/vnd.yamaha.openscoreformat.osfpvg+xml"},
        { "otc", "application/vnd.oasis.opendocument.chart-template"},
        { "otf", "application/x-font-otf"},
        { "otg", "application/vnd.oasis.opendocument.graphics-template"},
        { "oth", "application/vnd.oasis.opendocument.text-web"},
        { "oti", "application/vnd.oasis.opendocument.image-template"},
        { "otm", "application/vnd.oasis.opendocument.text-master"},
        { "otp", "application/vnd.oasis.opendocument.presentation-template"},
        { "ots", "application/vnd.oasis.opendocument.spreadsheet-template"},
        { "ott", "application/vnd.oasis.opendocument.text-template"},
        { "oxt", "application/vnd.openofficeorg.extension"},
        { "p10", "application/pkcs10"},
        { "p12", "application/x-pkcs12"},
        { "p7b", "application/x-pkcs7-certificates"},
        { "p7c", "application/x-pkcs7-mime"},
        { "p7m", "application/x-pkcs7-mime"},
        { "p7r", "application/x-pkcs7-certreqresp"},
        { "p7s", "application/x-pkcs7-signature"},
        { "pas", "text/x-pascal"},
        { "pbd", "application/vnd.powerbuilder6"},
        { "pbm", "image/x-portable-bitmap"},
        { "pcf", "application/x-font-pcf"},
        { "pcl", "application/vnd.hp-pcl"},
        { "pclxl", "application/vnd.hp-pclxl"},
        { "pct", "image/x-pict"},
        { "pcurl", "application/vnd.curl.pcurl"},
        { "pcx", "image/x-pcx"},
        { "pdb", "application/vnd.palm"},
        { "pdf", "application/pdf"},
        { "pfa", "application/x-font-type1"},
        { "pfb", "application/x-font-type1"},
        { "pfm", "application/x-font-type1"},
        { "pfr", "application/font-tdpfr"},
        { "pfx", "application/x-pkcs12"},
        { "pgm", "image/x-portable-graymap"},
        { "pgn", "application/x-chess-pgn"},
        { "pgp", "application/pgp-encrypted"},
        { "pic", "image/x-pict"},
        { "pkg", "application/octet-stream"},
        { "pki", "application/pkixcmp"},
        { "pkipath", "application/pkix-pkipath"},
        { "pko", "application/ynd.ms-pkipko"},
        { "plb", "application/vnd.3gpp.pic-bw-large"},
        { "plc", "application/vnd.mobius.plc"},
        { "plf", "application/vnd.pocketlearn"},
        { "pls", "application/pls+xml"},
        { "pl", "text/plain"},
        { "pma", "application/x-perfmon"},
        { "pmc", "application/x-perfmon"},
        { "pml", "application/x-perfmon"},
        { "pmr", "application/x-perfmon"},
        { "pmw", "application/x-perfmon"},
        { "png", "image/png"},
        { "pnm", "image/x-portable-anymap"},
        { "portpkg", "application/vnd.macports.portpkg"},
        { "pot,", "application/vnd.ms-powerpoint"},
        { "pot", "application/vnd.ms-powerpoint"},
        { "potm", "application/vnd.ms-powerpoint.template.macroenabled.12"},
        { "potx", "application/vnd.openxmlformats-officedocument.presentationml.template"},
        { "ppa", "application/vnd.ms-powerpoint"},
        { "ppam", "application/vnd.ms-powerpoint.addin.macroenabled.12"},
        { "ppd", "application/vnd.cups-ppd"},
        { "ppm", "image/x-portable-pixmap"},
        { "pps", "application/vnd.ms-powerpoint"},
        { "ppsm", "application/vnd.ms-powerpoint.slideshow.macroenabled.12"},
        { "ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
        { "ppt", "application/vnd.ms-powerpoint"},
        { "pptm", "application/vnd.ms-powerpoint.presentation.macroenabled.12"},
        { "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
        { "pqa", "application/vnd.palm"},
        { "prc", "application/x-mobipocket-ebook"},
        { "pre", "application/vnd.lotus-freelance"},
        { "prf", "application/pics-rules"},
        { "ps", "application/postscript"},
        { "psb", "application/vnd.3gpp.pic-bw-small"},
        { "psd", "image/vnd.adobe.photoshop"},
        { "psf", "application/x-font-linux-psf"},
        { "p", "text/x-pascal"},
        { "ptid", "application/vnd.pvi.ptid1"},
        { "pub", "application/x-mspublisher"},
        { "pvb", "application/vnd.3gpp.pic-bw-var"},
        { "pwn", "application/vnd.3m.post-it-notes"},
        { "pwz", "application/vnd.ms-powerpoint"},
        { "pya", "audio/vnd.ms-playready.media.pya"},
        { "pyc", "application/x-python-code"},
        { "pyo", "application/x-python-code"},
        { "py", "text/x-python"},
        { "pyv", "video/vnd.ms-playready.media.pyv"},
        { "qam", "application/vnd.epson.quickanime"},
        { "qbo", "application/vnd.intu.qbo"},
        { "qfx", "application/vnd.intu.qfx"},
        { "qps", "application/vnd.publishare-delta-tree"},
        { "qt", "video/quicktime"},
        { "qwd", "application/vnd.quark.quarkxpress"},
        { "qwt", "application/vnd.quark.quarkxpress"},
        { "qxb", "application/vnd.quark.quarkxpress"},
        { "qxd", "application/vnd.quark.quarkxpress"},
        { "qxl", "application/vnd.quark.quarkxpress"},
        { "qxt", "application/vnd.quark.quarkxpress"},
        { "ra", "audio/x-pn-realaudio"},
        { "ram", "audio/x-pn-realaudio"},
        { "rar", "application/x-rar-compressed"},
        { "ras", "image/x-cmu-raster"},
        { "rcprofile", "application/vnd.ipunplugged.rcprofile"},
        { "rdf", "application/rdf+xml"},
        { "rdz", "application/vnd.data-vision.rdz"},
        { "rep", "application/vnd.businessobjects"},
        { "res", "application/x-dtbresource+xml"},
        { "rgb", "image/x-rgb"},
        { "rif", "application/reginfo+xml"},
        { "rl", "application/resource-lists+xml"},
        { "rlc", "image/vnd.fujixerox.edmics-rlc"},
        { "rld", "application/resource-lists-diff+xml"},
        { "rm", "application/vnd.rn-realmedia"},
        { "rmi", "audio/midi"},
        { "rmp", "audio/x-pn-realaudio-plugin"},
        { "rms", "application/vnd.jcp.javame.midlet-rms"},
        { "rnc", "application/relax-ng-compact-syntax"},
        { "roff", "text/troff"},
        { "rpm", "application/x-rpm"},
        { "rpss", "application/vnd.nokia.radio-presets"},
        { "rpst", "application/vnd.nokia.radio-preset"},
        { "rq", "application/sparql-query"},
        { "rs", "application/rls-services+xml"},
        { "rsd", "application/rsd+xml"},
        { "rss", "application/rss+xml"},
        { "rtf", "application/rtf"},
        { "rtx", "text/richtext"},
        { "saf", "application/vnd.yamaha.smaf-audio"},
        { "sbml", "application/sbml+xml"},
        { "sc", "application/vnd.ibm.secure-container"},
        { "scd", "application/x-msschedule"},
        { "scm", "application/vnd.lotus-screencam"},
        { "scq", "application/scvp-cv-request"},
        { "scs", "application/scvp-cv-response"},
        { "sct", "text/scriptlet"},
        { "scurl", "text/vnd.curl.scurl"},
        { "sda", "application/vnd.stardivision.draw"},
        { "sdc", "application/vnd.stardivision.calc"},
        { "sdd", "application/vnd.stardivision.impress"},
        { "sdkd", "application/vnd.solent.sdkm+xml"},
        { "sdkm", "application/vnd.solent.sdkm+xml"},
        { "sdp", "application/sdp"},
        { "sdw", "application/vnd.stardivision.writer"},
        { "see", "application/vnd.seemail"},
        { "seed", "application/vnd.fdsn.seed"},
        { "sema", "application/vnd.sema"},
        { "semd", "application/vnd.semd"},
        { "semf", "application/vnd.semf"},
        { "ser", "application/java-serialized-object"},
        { "setpay", "application/set-payment-initiation"},
        { "setreg", "application/set-registration-initiation"},
        { "sfd-hdstx", "application/vnd.hydrostatix.sof-data"},
        { "sfs", "application/vnd.spotfire.sfs"},
        { "sgl", "application/vnd.stardivision.writer-global"},
        { "sgml", "text/sgml"},
        { "sgm", "text/sgml"},
        { "sh", "application/x-sh"},
        { "shar", "application/x-shar"},
        { "shf", "application/shf+xml"},
        { "sic", "application/vnd.wap.sic"},
        { "sig", "application/pgp-signature"},
        { "silo", "model/mesh"},
        { "sis", "application/vnd.symbian.install"},
        { "sisx", "application/vnd.symbian.install"},
        { "sit", "application/x-stuffit"},
        { "si", "text/vnd.wap.si"},
        { "sitx", "application/x-stuffitx"},
        { "skd", "application/vnd.koan"},
        { "skm", "application/vnd.koan"},
        { "skp", "application/vnd.koan"},
        { "skt", "application/vnd.koan"},
        { "slc", "application/vnd.wap.slc"},
        { "sldm", "application/vnd.ms-powerpoint.slide.macroenabled.12"},
        { "sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide"},
        { "slt", "application/vnd.epson.salt"},
        { "sl", "text/vnd.wap.sl"},
        { "smf", "application/vnd.stardivision.math"},
        { "smi", "application/smil+xml"},
        { "smil", "application/smil+xml"},
        { "snd", "audio/basic"},
        { "snf", "application/x-font-snf"},
        { "so", "application/octet-stream"},
        { "spc", "application/x-pkcs7-certificates"},
        { "spf", "application/vnd.yamaha.smaf-phrase"},
        { "spl", "application/x-futuresplash"},
        { "spot", "text/vnd.in3d.spot"},
        { "spp", "application/scvp-vp-response"},
        { "spq", "application/scvp-vp-request"},
        { "spx", "audio/ogg"},
        { "src", "application/x-wais-source"},
        { "srx", "application/sparql-results+xml"},
        { "sse", "application/vnd.kodak-descriptor"},
        { "ssf", "application/vnd.epson.ssf"},
        { "ssml", "application/ssml+xml"},
        { "sst", "application/vnd.ms-pkicertstore"},
        { "stc", "application/vnd.sun.xml.calc.template"},
        { "std", "application/vnd.sun.xml.draw.template"},
        { "s", "text/x-asm"},
        { "stf", "application/vnd.wt.stf"},
        { "sti", "application/vnd.sun.xml.impress.template"},
        { "stk", "application/hyperstudio"},
        { "stl", "application/vnd.ms-pki.stl"},
        { "stm", "text/html"},
        { "str", "application/vnd.pg.format"},
        { "stw", "application/vnd.sun.xml.writer.template"},
        { "sus", "application/vnd.sus-calendar"},
        { "susp", "application/vnd.sus-calendar"},
        { "sv4cpio", "application/x-sv4cpio"},
        { "sv4crc", "application/x-sv4crc"},
        { "svd", "application/vnd.svd"},
        { "svg", "image/svg+xml"},
        { "svgz", "image/svg+xml"},
        { "swa", "application/x-director"},
        { "swf", "application/x-shockwave-flash"},
        { "swi", "application/vnd.arastra.swi"},
        { "sxc", "application/vnd.sun.xml.calc"},
        { "sxd", "application/vnd.sun.xml.draw"},
        { "sxg", "application/vnd.sun.xml.writer.global"},
        { "sxi", "application/vnd.sun.xml.impress"},
        { "sxm", "application/vnd.sun.xml.math"},
        { "sxw", "application/vnd.sun.xml.writer"},
        { "tao", "application/vnd.tao.intent-module-archive"},
        { "t", "application/x-troff"},
        { "tar", "application/x-tar"},
        { "tcap", "application/vnd.3gpp2.tcap"},
        { "tcl", "application/x-tcl"},
        { "teacher", "application/vnd.smart.teacher"},
        { "tex", "application/x-tex"},
        { "texi", "application/x-texinfo"},
        { "texinfo", "application/x-texinfo"},
        { "text", "text/plain"},
        { "tfm", "application/x-tex-tfm"},
        { "tgz", "application/x-gzip"},
        { "tiff", "image/tiff"},
        { "tif", "image/tiff"},
        { "tmo", "application/vnd.tmobile-livetv"},
        { "torrent", "application/x-bittorrent"},
        { "tpl", "application/vnd.groove-tool-template"},
        { "tpt", "application/vnd.trid.tpt"},
        { "tra", "application/vnd.trueapp"},
        { "trm", "application/x-msterminal"},
        { "tr", "text/troff"},
        { "tsv", "text/tab-separated-values"},
        { "ttc", "application/x-font-ttf"},
        { "ttf", "application/x-font-ttf"},
        { "twd", "application/vnd.simtech-mindmapper"},
        { "twds", "application/vnd.simtech-mindmapper"},
        { "txd", "application/vnd.genomatix.tuxedo"},
        { "txf", "application/vnd.mobius.txf"},
        { "txt", "text/plain"},
        { "u32", "application/x-authorware-bin"},
        { "udeb", "application/x-debian-package"},
        { "ufd", "application/vnd.ufdl"},
        { "ufdl", "application/vnd.ufdl"},
        { "uls", "text/iuls"},
        { "umj", "application/vnd.umajin"},
        { "unityweb", "application/vnd.unity"},
        { "uoml", "application/vnd.uoml+xml"},
        { "uris", "text/uri-list"},
        { "uri", "text/uri-list"},
        { "urls", "text/uri-list"},
        { "ustar", "application/x-ustar"},
        { "utz", "application/vnd.uiq.theme"},
        { "uu", "text/x-uuencode"},
        { "vcd", "application/x-cdlink"},
        { "vcf", "text/x-vcard"},
        { "vcg", "application/vnd.groove-vcard"},
        { "vcs", "text/x-vcalendar"},
        { "vcx", "application/vnd.vcx"},
        { "vis", "application/vnd.visionary"},
        { "viv", "video/vnd.vivo"},
        { "vor", "application/vnd.stardivision.writer"},
        { "vox", "application/x-authorware-bin"},
        { "vrml", "x-world/x-vrml"},
        { "vsd", "application/vnd.visio"},
        { "vsf", "application/vnd.vsf"},
        { "vss", "application/vnd.visio"},
        { "vst", "application/vnd.visio"},
        { "vsw", "application/vnd.visio"},
        { "vtu", "model/vnd.vtu"},
        { "vxml", "application/voicexml+xml"},
        { "w3d", "application/x-director"},
        { "wad", "application/x-doom"},
        { "wav", "audio/x-wav"},
        { "wax", "audio/x-ms-wax"},
        { "wbmp", "image/vnd.wap.wbmp"},
        { "wbs", "application/vnd.criticaltools.wbs+xml"},
        { "wbxml", "application/vnd.wap.wbxml"},
        { "wcm", "application/vnd.ms-works"},
        { "wdb", "application/vnd.ms-works"},
        { "wiz", "application/msword"},
        { "wks", "application/vnd.ms-works"},
        { "wma", "audio/x-ms-wma"},
        { "wmd", "application/x-ms-wmd"},
        { "wmf", "application/x-msmetafile"},
        { "wmlc", "application/vnd.wap.wmlc"},
        { "wmlsc", "application/vnd.wap.wmlscriptc"},
        { "wmls", "text/vnd.wap.wmlscript"},
        { "wml", "text/vnd.wap.wml"},
        { "wm", "video/x-ms-wm"},
        { "wmv", "video/x-ms-wmv"},
        { "wmx", "video/x-ms-wmx"},
        { "wmz", "application/x-ms-wmz"},
        { "wpd", "application/vnd.wordperfect"},
        { "wpl", "application/vnd.ms-wpl"},
        { "wps", "application/vnd.ms-works"},
        { "wqd", "application/vnd.wqd"},
        { "wri", "application/x-mswrite"},
        { "wrl", "x-world/x-vrml"},
        { "wrz", "x-world/x-vrml"},
        { "wsdl", "application/wsdl+xml"},
        { "wspolicy", "application/wspolicy+xml"},
        { "wtb", "application/vnd.webturbo"},
        { "wvx", "video/x-ms-wvx"},
        { "x32", "application/x-authorware-bin"},
        { "x3d", "application/vnd.hzn-3d-crossword"},
        { "xaf", "x-world/x-vrml"},
        { "xap", "application/x-silverlight-app"},
        { "xar", "application/vnd.xara"},
        { "xbap", "application/x-ms-xbap"},
        { "xbd", "application/vnd.fujixerox.docuworks.binder"},
        { "xbm", "image/x-xbitmap"},
        { "xdm", "application/vnd.syncml.dm+xml"},
        { "xdp", "application/vnd.adobe.xdp+xml"},
        { "xdw", "application/vnd.fujixerox.docuworks"},
        { "xenc", "application/xenc+xml"},
        { "xer", "application/patch-ops-error+xml"},
        { "xfdf", "application/vnd.adobe.xfdf"},
        { "xfdl", "application/vnd.xfdl"},
        { "xht", "application/xhtml+xml"},
        { "xhtml", "application/xhtml+xml"},
        { "xhvml", "application/xv+xml"},
        { "xif", "image/vnd.xiff"},
        { "xla", "application/vnd.ms-excel"},
        { "xlam", "application/vnd.ms-excel.addin.macroenabled.12"},
        { "xlb", "application/vnd.ms-excel"},
        { "xlc", "application/vnd.ms-excel"},
        { "xlm", "application/vnd.ms-excel"},
        { "xls", "application/vnd.ms-excel"},
        { "xlsb", "application/vnd.ms-excel.sheet.binary.macroenabled.12"},
        { "xlsm", "application/vnd.ms-excel.sheet.macroenabled.12"},
        { "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
        { "xlt", "application/vnd.ms-excel"},
        { "xltm", "application/vnd.ms-excel.template.macroenabled.12"},
        { "xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"},
        { "xlw", "application/vnd.ms-excel"},
        { "xml", "application/xml"},
        { "xo", "application/vnd.olpc-sugar"},
        { "xof", "x-world/x-vrml"},
        { "xop", "application/xop+xml"},
        { "xpdl", "application/xml"},
        { "xpi", "application/x-xpinstall"},
        { "xpm", "image/x-xpixmap"},
        { "xpr", "application/vnd.is-xpr"},
        { "xps", "application/vnd.ms-xpsdocument"},
        { "xpw", "application/vnd.intercon.formnet"},
        { "xpx", "application/vnd.intercon.formnet"},
        { "xsl", "application/xml"},
        { "xslt", "application/xslt+xml"},
        { "xsm", "application/vnd.syncml+xml"},
        { "xspf", "application/xspf+xml"},
        { "xul", "application/vnd.mozilla.xul+xml"},
        { "xvm", "application/xv+xml"},
        { "xvml", "application/xv+xml"},
        { "xwd", "image/x-xwindowdump"},
        { "xyz", "chemical/x-xyz"},
        { "z", "application/x-compress"},
        { "zaz", "application/vnd.zzazz.deck+xml"},
        { "zip", "application/zip"},
        { "zir", "application/vnd.zul"},
        { "zirz", "application/vnd.zul"},
        { "zmm", "application/vnd.handheld-entertainment+xml"}
    };



    public static String unfold(String s)
    {
        if (s == null)
        {
            return null;
        }
        return s.replaceAll("\r|\n", "");
    }

    public static String decode(String s)
    {
        if (s == null)
        {
            return null;
        }
        return DecoderUtil.decodeEncodedWords(s);
    }

    public static String unfoldAndDecode(String s)
    {
        return decode(unfold(s));
    }

    // TODO implement proper foldAndEncode
    public static String foldAndEncode(String s)
    {
        return s;
    }

    /**
     * Returns the named parameter of a header field. If name is null the first
     * parameter is returned, or if there are no additional parameters in the
     * field the entire field is returned. Otherwise the named parameter is
     * searched for in a case insensitive fashion and returned. If the parameter
     * cannot be found the method returns null.
     *
     * @param header
     * @param name
     * @return
     */
    public static String getHeaderParameter(String header, String name)
    {
        if (header == null)
        {
            return null;
        }
        header = header.replaceAll("\r|\n", "");
        String[] parts = header.split(";");
        if (name == null)
        {
            return parts[0];
        }
        for (String part : parts)
        {
            if (part.trim().toLowerCase().startsWith(name.toLowerCase()))
            {
                String parameter = part.split("=", 2)[1].trim();
                if (parameter.startsWith("\"") && parameter.endsWith("\""))
                {
                    return parameter.substring(1, parameter.length() - 1);
                }
                else
                {
                    return parameter;
                }
            }
        }
        return null;
    }

    public static Part findFirstPartByMimeType(Part part, String mimeType)
    throws MessagingException
    {
        if (part.getBody() instanceof Multipart)
        {
            Multipart multipart = (Multipart)part.getBody();
            for (int i = 0, count = multipart.getCount(); i < count; i++)
            {
                BodyPart bodyPart = multipart.getBodyPart(i);
                Part ret = findFirstPartByMimeType(bodyPart, mimeType);
                if (ret != null)
                {
                    return ret;
                }
            }
        }
        else if (part.getMimeType().equalsIgnoreCase(mimeType))
        {
            return part;
        }
        return null;
    }

    public static Part findPartByContentId(Part part, String contentId) throws Exception
    {
        if (part.getBody() instanceof Multipart)
        {
            Multipart multipart = (Multipart)part.getBody();
            for (int i = 0, count = multipart.getCount(); i < count; i++)
            {
                BodyPart bodyPart = multipart.getBodyPart(i);
                Part ret = findPartByContentId(bodyPart, contentId);
                if (ret != null)
                {
                    return ret;
                }
            }
        }
        String[] header = part.getHeader("Content-ID");
        if (header != null)
        {
            for (String s : header)
            {
                if (s.equals(contentId))
                {
                    return part;
                }
            }
        }
        return null;
    }

    /**
      * Reads the Part's body and returns a String based on any charset conversion that needed
      * to be done.
      * @param part The part containing a body
      * @return a String containing the converted text in the body, or null if there was no text
      * or an error during conversion.
      */
    public static String getTextFromPart(Part part)
    {
        try
        {
            if ((part != null) && (part.getBody() != null))
            {
                final Body body = part.getBody();
                if (body instanceof TextBody)
                {
                    return ((TextBody)body).getText();
                }

                final String mimeType = part.getMimeType();
                if ((mimeType != null) && MimeUtility.mimeTypeMatches(mimeType, "text/*"))
                {
                    /*
                     * We've got a text part, so let's see if it needs to be processed further.
                     */
                    final String originalCharset = getHeaderParameter(part.getContentType(), "charset");
                    String charset = "ASCII";   // No encoding, so use us-ascii, which is the standard.
                    if ((originalCharset != null) && (!"0".equals(originalCharset)))
                    {
                        /*
                         * See if there is conversion from the MIME charset to the Java one.
                         */

                        charset = Charset.forName(fixupCharset(originalCharset)).name();

                        if (charset == null)
                        {
                            Log.e(K9.LOG_TAG,"I don't know how to deal with the charset "+originalCharset+". Falling back to US-ASCII");
                            charset = "US-ASCII";
                        }
                    }

                    /*
                     * Now we read the part into a buffer for further processing. Because
                     * the stream is now wrapped we'll remove any transfer encoding at this point.
                     */
                    InputStream in = part.getBody().getInputStream();
                    ByteArrayOutputStream out = new ByteArrayOutputStream(in.available());
                    IOUtils.copy(in, out);
                    in.close();
                    in = null;      // we want all of our memory back, and close might not release
                    // Cargo culted from AOSP - This disagrees with the platform docs

                    /*
                     * Convert and return as new String
                     */
                    final String result = out.toString(charset);
                    out.close();
                    return result;
                }
            }

        }
        catch (OutOfMemoryError oom)
        {
            /*
             * If we are not able to process the body there's nothing we can do about it. Return
             * null and let the upper layers handle the missing content.
             */
            Log.e(K9.LOG_TAG, "Unable to getTextFromPart " + oom.toString());
        }
        catch (Exception e)
        {
            /*
             * If we are not able to process the body there's nothing we can do about it. Return
             * null and let the upper layers handle the missing content.
             */
            Log.e(K9.LOG_TAG, "Unable to getTextFromPart", e);
        }
        return null;
    }

    /**
     * Returns true if the given mimeType matches the matchAgainst specification.
     * @param mimeType A MIME type to check.
     * @param matchAgainst A MIME type to check against. May include wildcards such as image/* or
     * * /*.
     * @return
     */
    public static boolean mimeTypeMatches(String mimeType, String matchAgainst)
    {
        Pattern p = Pattern.compile(matchAgainst.replaceAll("\\*", "\\.\\*"), Pattern.CASE_INSENSITIVE);
        return p.matcher(mimeType).matches();
    }

    /**
     * Returns true if the given mimeType matches any of the matchAgainst specifications.
     * @param mimeType A MIME type to check.
     * @param matchAgainst An array of MIME types to check against. May include wildcards such
     * as image/* or * /*.
     * @return
     */
    public static boolean mimeTypeMatches(String mimeType, String[] matchAgainst)
    {
        for (String matchType : matchAgainst)
        {
            if (mimeTypeMatches(mimeType, matchType))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Removes any content transfer encoding from the stream and returns a Body.
     */
    public static Body decodeBody(InputStream in, String contentTransferEncoding)
    throws IOException
    {
        /*
         * We'll remove any transfer encoding by wrapping the stream.
         */
        if (contentTransferEncoding != null)
        {
            contentTransferEncoding =
            MimeUtility.getHeaderParameter(contentTransferEncoding, null);
            if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding))
            {
                in = new QuotedPrintableInputStream(in);
            }
            else if ("base64".equalsIgnoreCase(contentTransferEncoding))
            {
                in = new Base64InputStream(in);
            }
        }

        BinaryTempFileBody tempBody = new BinaryTempFileBody();
        OutputStream out = tempBody.getOutputStream();
        IOUtils.copy(in, out);
        out.close();
        return tempBody;
    }

    /**
     * An unfortunately named method that makes decisions about a Part (usually a Message)
     * as to which of it's children will be "viewable" and which will be attachments.
     * The method recursively sorts the viewables and attachments into seperate
     * lists for further processing.
     * @param part
     * @param viewables
     * @param attachments
     * @throws MessagingException
     */
    public static void collectParts(Part part, ArrayList<Part> viewables,
    ArrayList<Part> attachments) throws MessagingException
    {
        /*
         * If the part is Multipart but not alternative it's either mixed or
         * something we don't know about, which means we treat it as mixed
         * per the spec. We just process it's pieces recursively.
         */
        if (part.getBody() instanceof Multipart)
        {
            Multipart mp = (Multipart)part.getBody();
            for (int i = 0; i < mp.getCount(); i++)
            {
                collectParts(mp.getBodyPart(i), viewables, attachments);
            }
        }
        /*
         * If the part is an embedded message we just continue to process
         * it, pulling any viewables or attachments into the running list.
         */
        else if (part.getBody() instanceof Message)
        {
            Message message = (Message)part.getBody();
            collectParts(message, viewables, attachments);
        }
        /*
         * If the part is HTML and it got this far it's part of a mixed (et
         * al) and should be rendered inline.
         */
        else if (isPartTextualBody(part))
        {
            viewables.add(part);
        }
        else
        {
            attachments.add(part);
        }

    }


    public static Boolean isPartTextualBody(Part part) throws MessagingException
    {
        String disposition = part.getDisposition();
        String dispositionType = null;
        String dispositionFilename = null;
        if (disposition != null)
        {
            dispositionType = MimeUtility.getHeaderParameter(disposition, null);
            dispositionFilename = MimeUtility.getHeaderParameter(disposition, "filename");
        }

        /*
         * A best guess that this part is intended to be an attachment and not inline.
         */
        boolean attachment = ("attachment".equalsIgnoreCase(dispositionType) || (dispositionFilename != null));

        if ((!attachment) && (part.getMimeType().equalsIgnoreCase("text/html")))
        {
            return true;
        }
        /*
         * If the part is plain text and it got this far it's part of a
         * mixed (et al) and should be rendered inline.
         */
        else if ((!attachment) && (part.getMimeType().equalsIgnoreCase("text/plain")))
        {
            return true;
        }
        /*
         * Finally, if it's nothing else we will include it as an attachment.
         */
        else
        {
            return false;
        }
    }


    public static String getMimeTypeByExtension(String filename)
    {
        String returnedType = null;
        String extension = null;

        if (filename != null && filename.lastIndexOf('.') != -1)
        {
            extension = filename.substring(filename.lastIndexOf('.')+1).toLowerCase();
            returnedType = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
        }
        if (returnedType != null)
        {
            return returnedType;
        }
        else if (extension != null)
        {
            for (String[] contentTypeMapEntry : MIME_TYPE_BY_EXTENSION_MAP)
            {
                if (contentTypeMapEntry[0].equals(extension))
                {
                    return contentTypeMapEntry[1];
                }
            }
        }

        return DEFAULT_ATTACHMENT_MIME_TYPE;
    }


    private static String fixupCharset(String charset)
    {
        charset = charset.toLowerCase();
        if (charset.equals("cp932"))
            return "shift-jis";
        else if (charset.equals("koi8-u"))
            return "koi8-r";

        return charset;

    }


}
